#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <malloc.h>
#include "automata2.h"
#include "dfa.h"

void nfaToDfa(t_table * t)
{
    //si pasa esto todavia hay dobles sin abrir
    
    while (t->states.dim > t->transitions.fils)
    {                 
        addStates(t->states.vec[t->transitions.fils],t);    
    }

    removeNodes(t);
    printStates(t);
    printTable(t);
    printf("Conversion nfa-dfa lista\n");    
    
}

void addStates(int estadoNuevo, t_table * t)
{
     
    int procesoEstado,j=0,i;     
    t_int_vector * toca;     
    int destino,indice=-1;  


    if((toca = malloc(sizeof(t_int_vector)*t->transitions.cols))== NULL)
        error(1,"Could not allocate memory. Shame on you.");
    
    for(i=0;i<t->transitions.cols;i++)
    {

       if((toca[i].vec=malloc(sizeof(int)*t->transitions.fils))== NULL)
                 error(1,"Could not allocate memory. Shame on you.");
       
       for(j=0;j<t->transitions.fils;j++)
               toca[i].vec[j]=-1;       
       toca[i].dim=0;

    }   
     
     procesoEstado=estadoNuevo-t->originalDim;       
     
     j=0;
     while (procesoEstado>0)
     {     
           if (procesoEstado % 2)
           {
              for(i=0;i<t->transitions.cols;i++)
              {
          	          if(t->transitions.data[j][i] < t->originalDim)    
                         toca[i].vec[toca[i].dim++]=t->transitions.data[j][i];
                      else   
                         toca[i].vec[toca[i].dim++]=t->states.vec[t->transitions.data[j][i]];                         
              }                                              
           }
           procesoEstado/=2;
           j++;
     }

   for(i=0;i<t->transitions.cols;i++)        
   {   
         destino=processVector(t,&toca[i]);         
         indice=getStateIndex(t,destino);                                  	         
         t->transitions.data[t->transitions.fils][i]=indice;             
         free(toca[i].vec);
    }    
    
    addRow(t);    
    
    free(toca);
        
}


void addRow(t_table * t)
{
  int i,j;
  t->transitions.fils++;
 // Se jode con el realloc
 if (t->transitions.fils>=t->transitions.dimFils)
 {
  t->transitions.dimFils+=10;	
  if((t->transitions.data = realloc(t->transitions.data,t->transitions.dimFils*sizeof(int *)))== NULL)
        error(1,"Could not allocate memory. Shame on you.");  
  for(i=t->transitions.fils;i<t->transitions.dimFils;i++)         
  {
  	t->transitions.data[i]=malloc(sizeof(int)*t->transitions.cols);  	
  	for(j=0;j<t->transitions.cols;j++)	
  		t->transitions.data[i][j]=-1;
  }
  	 	
}

}
int processVector(t_table * t,t_int_vector * vector)
{
    int i;
    int newState=-1;
    
	for(i=0;i<vector->dim;i++)			    
       newState=composeStates(t->originalDim,newState,vector->vec[i]);
    return newState;

    
}
void insertInResult(t_int_vector * vector,int num)
{
     int i, add=1;
     if (num==-1)
        add=0;
     for(i=0;i<vector->dim && add;i++)     
        if (vector->vec[i]==num)        
           add=0;        
        
     if (add)
        vector->vec[vector->dim++]=num;
     return;                                
}
void removeNodes(t_table * t)
{
     int i,j,h=0;
     int * aux;
     t_int_vector statesAux;
     
     markNodes(t,t->iniState);
     
     
     statesAux.dim=0;
     int ** replace;
     
     if((replace = malloc(sizeof(int*)*2))==NULL)
                error(1,"Could not allocate memory. Shame on you.");                 
     if((replace[0] = malloc(sizeof(int)*t->transitions.fils))==NULL)
               error(1,"Could not allocate memory. Shame on you.");                 
     if((replace[1] = malloc(sizeof(int)*t->transitions.fils))==NULL)
               error(1,"Could not allocate memory. Shame on you.");                      
     
     if((statesAux.vec = malloc(t->states.dim*sizeof(int)))==NULL)
                 error(1,"Could not allocate memory. Shame on you.");                 
     
     for(i=0;i<(t->transitions.fils);i++)
     {     
         if  (t->transitions.data[i][t->transitions.cols-1]==-5) 
         {
             statesAux.vec[statesAux.dim]=t->states.vec[i];             
             if (i!=statesAux.dim)
             {
                  replace[0][h]=i;
                  replace[1][h++]=statesAux.dim;                  
                  for(j=0;j<t->transitions.cols;j++)
                      t->transitions.data[statesAux.dim][j]=changeValue(t->transitions.data[i][j],replace,h);
             }                                       
             t->transitions.data[statesAux.dim][t->transitions.cols-1]=-1;   
             statesAux.dim++;
         }                   
         else
             removeFromFinal(t,t->states.vec[i]);
     }    

     
     t->transitions.fils=statesAux.dim;
     //  Se deria achicar el espacio reservado para la matriz
     if((t->transitions.data = realloc(t->transitions.data,t->transitions.fils*sizeof(int *)))== NULL)
        error(1,"Could not allocate memory. Shame on you.");     
     
     if(h>0)
     {
          for(i=0;i<(t->transitions.fils);i++)
            for(j=0;j<t->transitions.cols;j++)
               t->transitions.data[i][j]=changeValue(t->transitions.data[i][j],replace,h);
 
     }
     adjustFinalStates(t);
     free(replace[1]);
     free(replace[0]);
     free(replace);     
     t->states.dim=statesAux.dim;
     aux=t->states.vec;
     t->states.vec=statesAux.vec;
     free(aux);
}
void markNodes(t_table * t,int state)
{

     int i,aux;
     t->transitions.data[state][t->transitions.cols-1]=-5;
     for(i=0;i<(t->transitions.cols-1);i++)
     {
         //where is pointing
         aux=t->transitions.data[state][i];
         //check that state
         if  (aux!=-1 && t->transitions.data[aux][t->transitions.cols-1]!=-5)
                  markNodes(t,aux);
     }

}
int changeValue(int value,int ** replace,int dim)
{
    int j;
    for(j=0;j<dim;j++)
    {   
       if (replace[0][j]==value)
          return replace[1][j];
    }      
    
    return value;
}
void removeFromFinal(t_table * t,int value)
{
     int i=0;
     for(i=0;i<t->finalStates.dim;i++)     
     {
          if (t->finalStates.vec[i]==value)
          {
             t->finalStates.vec[i]=-1;
             return;
          }   
     }
}
void adjustFinalStates(t_table * t)
{
   t_int_vector aux;    
   int i;

   if((aux.vec = malloc(t->finalStates.dim * sizeof(int)))==NULL)
      error(1,"Could not allocate memory. Shame on you.");
   aux.dim=0;     

   for(i=0;i<t->finalStates.dim;i++)
       if (t->finalStates.vec[i]!=-1)       
          aux.vec[aux.dim++]=t->finalStates.vec[i];       
                              
   if((aux.vec = realloc(aux.vec,aux.dim * sizeof(int)))==NULL)
          error(1,"Could not allocate memory. Shame on you.");                                
          
   t->finalStates.dim=aux.dim;
   free(t->finalStates.vec);
   t->finalStates.vec=aux.vec;

}
